#ifndef TCPSERVER_H_
#define TCPSERVER_H_
#include <string>
#include <mutex>
#include <Afsocket.h>
#include <unordered_map>
#include "BufferReader.h"
#include "NetMgr.h"

typedef std::function<void(SOCKET)> NewConnectionCallback;

class Acceptor
{
public:
	Acceptor(WorkerThreadN* eventLoop);
	virtual ~Acceptor();

	void SetNewConnectionCallback(const NewConnectionCallback& cb)
	{
		new_connection_callback_ = cb;
	}

	int  Listen(std::string ip, uint16_t port);
	void Close();

private:
	void OnAccept();

	WorkerThreadN* event_loop_ = nullptr;
	std::mutex mutex_;
	AfTcpSocket tcp_socket_;
	ChannelPtr channel_ptr_;
	NewConnectionCallback new_connection_callback_;
};

class TcpServerCallback;
class TcpConnection : public std::enable_shared_from_this<TcpConnection>
{
public:
	using Ptr = std::shared_ptr<TcpConnection>;
	using DisconnectCallback = std::function<void(std::shared_ptr<TcpConnection> conn)>;
	using ReadCallback = std::function<bool(std::shared_ptr<TcpConnection> conn, xop::BufferReader& buffer)>;

	TcpConnection(WorkerThreadN* task_scheduler, socket_t sockfd)
	{
		is_closed_ = false;
		m_AfTcpSocket.hSock = sockfd;
		m_task_scheduler = task_scheduler;
		read_buffer_ = std::make_unique<xop::BufferReader>();


		channel_ = std::make_shared<Channel>(m_AfTcpSocket.hSock);

		//channel_->SetReadCallback(std::bind(&TcpConnection::HandleRead, this));
		channel_->SetReadCallback([this]() { this->HandleRead(); });
		channel_->EnableReading();

		int ret = m_task_scheduler->UpdateChannel(channel_);
		
	}
	WorkerThreadN* GetTaskScheduler() const
	{
		return m_task_scheduler;
	}

#if 0
	int32_t  UpdateChannel()
	{
		channel_ = std::make_shared<Channel>(m_AfTcpSocket.hSock);

		//channel_->SetReadCallback(std::bind(&TcpConnection::HandleRead, this));
		channel_->SetReadCallback([this]() { this->HandleRead(); });
		channel_->EnableReading();

		int ret = m_task_scheduler->UpdateChannel(channel_);

		return ret;
	}

	int32_t RemoveChannel()
	{
		int ret = m_task_scheduler->RemoveChannel(channel_);
		return ret;
	}
#endif
	void Close()
	{
		if (!is_closed_) 
		{
			is_closed_ = true;
			m_task_scheduler->RemoveChannel(channel_);

		
			if (disconnect_cb_) {
				disconnect_cb_(shared_from_this());
			}

		}
	}

	virtual ~TcpConnection()
	{
		m_AfTcpSocket.Close();
	}
	bool IsClosed() const
	{
		return is_closed_;
	}
	virtual void HandleRead();
	//virtual void HandleWrite();
	virtual void HandleClose();
	virtual void HandleError();

	int32_t Recv(char* data, int len)
	{
		int ret = 0;
		m_task_scheduler->InvokTask([this, &ret, &data, &len] {
			ret = m_AfTcpSocket.Recv(data, len);
			});
		return ret;
	}

	int32_t Send(char* data, int len)
	{
		int ret = 0;
		m_task_scheduler->InvokTask([this, &ret, &data, &len] {
			ret = m_AfTcpSocket.Send(data, len);
			});
		return ret;
	}
	int GetSocket()
	{
		return m_AfTcpSocket.hSock;
	}
	void SetDisconnectCallback(const DisconnectCallback& cb)
	{
		disconnect_cb_ = cb;
	}
	void SetReadCallback(const ReadCallback& cb)
	{
		read_cb_ = cb;
	}



	uint16_t GetPort() const
	{
		//return SocketUtil::GetPeerPort(channel_->GetSocket());
		AfSockAddr tAfSockAddr;
		int ret = m_AfTcpSocket.GetLocalAddr(tAfSockAddr);
		if (ret == 0)
		{
			return tAfSockAddr.GetPort();
		}
		return ret;
	}

	std::string GetIp() const
	{
		AfSockAddr tAfSockAddr;
		int ret = m_AfTcpSocket.GetLocalAddr(tAfSockAddr);
		if (ret == 0)
		{
			return tAfSockAddr.GetIp_str();
		}
		return "";
	}
private:
	std::shared_ptr<Channel> channel_;

	AfTcpSocket m_AfTcpSocket;
	WorkerThreadN* m_task_scheduler;
	DisconnectCallback disconnect_cb_;
	ReadCallback read_cb_;
	std::unique_ptr<xop::BufferReader> read_buffer_;
	bool is_closed_ = false;
};

class TcpServerCallback
{
public:
	virtual void OnRead(TcpConnection::Ptr oTcpConnect, xop::BufferReader& buffer) = 0;
};

class TcpServer
{
public:
	TcpServer();
	virtual ~TcpServer();

	virtual bool Start(std::string ip, uint16_t port);
	virtual void Stop();

	virtual TcpConnection::Ptr OnConnect(socket_t hSock);
	virtual void AddConnection(socket_t sockfd, TcpConnection::Ptr tcp_conn);
	virtual void RemoveConnection(socket_t sockfd);

	virtual bool OnRead(TcpConnection::Ptr oTcpConnect, xop::BufferReader& buffer);

	std::string GetIPAddress() const
	{
		return ip_;
	}

	uint16_t GetPort() const
	{
		return port_;
	}

protected:

	uint16_t port_;
	std::string ip_;
	bool is_started_=false;
	std::mutex mutex_;

	AfTcpSocket m_AfTcpSocket;
	//std::unordered_map<socket_t, TcpConnection::Ptr> connections_;
	std::unique_ptr<Acceptor> acceptor_;

	std::unordered_map<socket_t, TcpConnection::Ptr> connections_;
	//std::vector<char> m_readBuffer;
};

#endif